﻿using System;
using System.Collections.Generic;

namespace SingleBlog.Core.Services
{
    using Data;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Caching.Memory;
    using System.Linq;
    using System.Threading.Tasks;
    using Resources;

    /// <summary>
    /// 表示博客分类的管理服务。
    /// </summary>
    public class CategoryService
    {
        private SingleBlogDbContext _context;

        /// <summary>
        /// 初始化 <see cref="CategoryService"/> 类的新实例。
        /// </summary>
        /// <param name="cache">缓存注入。</param>
        /// <param name="context"><see cref="SingleBlogDbContext"/> 注入。</param>
        public CategoryService(SingleBlogDbContext context)
        {
            _context = context;
        }

        /// <summary>
        /// 以异步方式获取所有排序过的分类集合。
        /// <para>优先读取缓存。</para>
        /// </summary>
        /// <returns></returns>
        public Task<IEnumerable<Category>> GetCategoriesAsync()
        =>       
            Task.Run(()=>_context.Categories.Include(m=>m.Articles).AsNoTracking().OrderBy(m => m.OrderNo).ToList().AsEnumerable()
        );

        /// <summary>
        /// 以异步的方式保存分类。
        /// <para>当分类的 Id==0 时，表示新增一条记录，否则将更新指定Id值的其他字段。</para>
        /// </summary>
        /// <param name="category">要保存的分类对象。</param>
        /// <returns></returns>
        public async Task SaveCategoryAsync(Category category)
        {
            if (category == null)
            {
                throw new ArgumentNullException(nameof(category));
            }

            if (category.Id == 0)
            {
                _context.Categories.Add(category);
            }
            else
            {
                _context.Entry(category).State = EntityState.Modified;
            }
            await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 以异步方式获取指定id的分类。
        /// <para>将优先从缓存中读取。</para>
        /// </summary>
        /// <param name="id">要获取的分类Id。</param>
        /// <returns></returns>
        public Task<Category> GetCategoryAsync(int id)
        => _context.Categories.FindAsync(id);

        /// <summary>
        /// 以异步方式删除分类。
        /// <para>若当前分类有文章，将全部移动到“未分类”的分类下。</para>
        /// </summary>
        /// <param name="id">要删除的分类Id。</param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException">未找到要删除的分类。</exception>
        /// <exception cref="InvalidOperationException">删除的分类是系统分类 or 删除提交失败。</exception>
        public async Task DeleteCategoryAsync(int id)
        {
            var categoryToDelete = await _context.Categories.FindAsync(id);
            if (categoryToDelete == null)
            {
                throw new NullReferenceException(Language.CategoryNotFound.StringFormat(id));
            }

            if (categoryToDelete.IsSystem)
            {
                throw new InvalidOperationException(Language.CategoryCannotDeleted.StringFormat(id));
            }

            //移动相关文章到未分类

            foreach(var articles in categoryToDelete.Articles)
            {
                articles.Category = await _context.Categories.SingleOrDefaultAsync(m => m.Name == Category.DEFAULT_NAME);
            }

            _context.Categories.Remove(categoryToDelete);                        
            await _context.SaveChangesAsync();
        }
    }
}
